home *** CD-ROM | disk | FTP | other *** search
- /* popen.c
- *
- * Implementation of popen() / pclose for Atari ST (will eventually work for
- * MSDOS too). The pipe is simulated by a temporary file. If caller wants to
- * read the pipe, then execute the command in popen and return a descriptor
- * to the output delivered by the command. If caller wants to write to the
- * pipe, then preserve the callers output in a temp file and execute the
- * command on pclose.
- * Since it is necessary to keep some information from popen() up to the
- * pclose(), we keep all opened pipes in a list and fill up the entries as
- * needed. Pipes are identified by their FILE descriptor returned from the
- * fopen() call.
- *
- * Revision 1.2, jrb 08-15-89 applied kai's diffs
- * gcc-lib's system() now does re-direction. Changes to
- * for re-direction stuff because of this.
- *
- * Revision 1.1, kub 05-23-89
- * written 89/05/23 by Kai-Uwe Bloem (I5110401@DBSTU1.BITNET for now)
- */
-
- #include <stdio.h>
- #include <memory.h>
- #include <fcntl.h>
- #include <string.h>
- #include <unistd.h>
- #include "lib.h"
-
- struct _pipe {
- char pmode; /* "r" or "w" to/from the pipe ? */
- char *pcommand; /* cmd to execute (only for "w") */
- int pstat; /* exit code of cmd (only for "r") */
- char pname[32]; /* temp filename. 32 should be enough...*/
- FILE *pfile; /* pipe identifier */
- struct _pipe *pnext; /* next pipe in the list. */
- };
-
- static struct _pipe *__pipes = NULL; /* head of pipe list */
-
- /* open a pipe to the command argument in the mode given by the type string.
- * If caller wants to read the pipe, redirect output and execute command,
- * then open the temp file and return that. If caller wants to write to
- * the pipe, create the temp file and return that.
- */
- FILE *popen(command, type)
- const char *command, *type;
- {
- struct _pipe *p; /* the new pipe's list entry */
-
- /* get space for the new pipe. If we can't get it then that's that */
- p = (struct _pipe *) malloc(sizeof(struct _pipe));
- if (p == NULL) return (FILE *) NULL;
-
- /* initialize the new pipe entry */
- p->pmode = *type;
- p->pfile = (FILE *) NULL;
- (void)tmpnam(p->pname);
- /* make command line with appropriate re-direction */
- if((p->pcommand = (char *)malloc(strlen(command)+strlen(p->pname)+4L))
- == (char *)NULL)
- { /* no mem */
- free(p);
- return (FILE *)NULL;
- }
- strcpy(p->pcommand, command);
- strcat(p->pcommand, (p->pmode == 'r')? " >" : " <");
- strcat(p->pcommand, p->pname);
-
- /* Everything has now been set up to really execute the pipe request */
- switch(p->pmode)
- {
- case 'r': /* reading */
- /* execute the command, output redir. to tmp pipe file */
- p->pstat = system(p->pcommand);
- if (p->pstat < 0) {
- unlink(p->pname);
- return (FILE *)NULL;
- }
- p->pfile = fopen(p->pname,"r"); /* now open the pipe */
- break;
- case 'w': /* writing */
- /* open tmp pipe file */
- p->pfile = fopen(p->pname,"w"); /* open the pipe file */
- break;
- }
-
- if (p->pfile)
- { /* pipe successfully established. Link it to the list */
- p->pnext = __pipes;
- __pipes = p;
- return p->pfile;
- }
- else
- { /* if there is no pipe identifier then throw it away */
- unlink(p->pname);
- free(p->pcommand);
- free(p);
- return (FILE *) NULL;
- }
- }
-
- /* close a pipe created by popen(). If caller wanted to read the pipe, then
- * just do the cleanup and return the command's status code. If caller wanted
- * to write to the pipe, the work has just started. Close the tempfile, call
- * the command with input redirected to the temp file and cleanup after that.
- */
- int pclose(fp)
- FILE *fp;
- {
- struct _pipe *p, /* the pipe's list element */
- *q; /* predecessor of p in the list */
- int status = -1; /* return status of the command */
-
- /* search the pipe list for a pipe matching the FILE descriptor */
- for (p = __pipes, q = NULL; p && p->pfile != fp; q = p, p = p->pnext);
- if (p == NULL) /* Never had a popen() for this file... */
- return status; /* this pclose call makes no sense ! */
-
- fclose(p->pfile); /* close temp file */
- switch(p->pmode)
- {
- case 'w': /* writing */
- status = system(p->pcommand); /* execute the command */
- break;
- case 'r': /* reading */
- status = p->pstat; /* just get status code */
- break;
- }
- unlink(p->pname); /* temp file no longer needed */
-
- /* remove the pipe from the list */
- if (q) /* not the first in the list, unlink it from previous pipe */
- q->pnext = p->pnext;
- else /* first in the list, set new list head */
- __pipes = __pipes->pnext;
-
- /* Now free the pipe entry */
- free(p->pcommand);
- free(p);
-
- return status;
- }
-